// --------------------------------------------------------------------------------------------------------------------
// <copyright file="WorkItemStoreRepository.cs" company="Scrum for Team System">
//   None
// </copyright>
// <summary>
//   Defines the WorkItemStoreRepository type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace ScrumForTeamSystem.EventService.Services
{
    using System;

    using Microsoft.TeamFoundation.WorkItemTracking.Client;

    using ScrumForTeamSystem.EventService.Infrastructure;
    using ScrumForTeamSystem.EventService.Infrastructure.Interfaces;
    using ScrumForTeamSystem.EventService.Services.Properties;

    /// <summary>
    /// Defines the WorkItemStoreRepository type.
    /// </summary>
    internal class WorkItemStoreRepository : IWorkItemStoreRepository
    {
        /// <summary>
        /// Instance of the caching service
        /// </summary>
        private readonly ICachingService cachingService;

        /// <summary>
        /// Instance of the connection service
        /// </summary>
        private readonly IServerConnectionService connectionService;

        /// <summary>
        /// Initializes a new instance of the <see cref="WorkItemStoreRepository"/> class.
        /// </summary>
        /// <param name="connectionService">The connection service.</param>
        /// <param name="cachingService">The caching service.</param>
        public WorkItemStoreRepository(IServerConnectionService connectionService, ICachingService cachingService)
        {
            this.connectionService = connectionService;
            this.cachingService = cachingService;
        }

        /// <summary>
        /// Occurs when [action] event raised.
        /// </summary>
        public event EventHandler<ActionEventArgs> Message;

        /// <summary>
        /// Occurs when [exception action] event raised.
        /// </summary>
        public event EventHandler<ExceptionActionEventArgs> ExceptionMessage;

        /// <summary>
        /// Gets a value indicating whether this instance is subscribed.
        /// </summary>
        /// <value>
        /// <c>true</c> if this instance is subscribed; otherwise, <c>false</c>.
        /// </value>
        private bool IsSubscribed
        {
            get
            {
                return this.Message != null;
            }
        }

        /// <summary>
        /// Gets the work item store.
        /// </summary>
        /// <param name="tfsAddress">The TFS URL.</param>
        /// <returns>Instance of the source item store service</returns>
        public WorkItemStore GetWorkItemStore(string tfsAddress)
        {
            return this.GetWorkItemStore(tfsAddress, String.Empty);
        }

        /// <summary>
        /// Gets the work item store.
        /// </summary>
        /// <param name="tfsAddress">The tfs uri.</param>
        /// <param name="sessionId">The session id.</param>
        /// <exception cref="ServiceException"></exception>
        /// <returns>
        /// An instance of the work item store service
        /// </returns>
        public WorkItemStore GetWorkItemStore(string tfsAddress, string sessionId)
        {
            return this.GetWorkItemStore(tfsAddress, sessionId, Settings.Default.CacheWorkItemStores);
        }

        /// <summary>
        /// Determines whether [the specified TFS] [has server connection].
        /// </summary>
        /// <param name="tfs">The TFS instance.</param>
        /// <returns>
        /// <c>true</c> if [the specified TFS] [has server connection]; otherwise, <c>false</c>.
        /// </returns>
        private static bool HasServerConnection(IServiceProvider tfs)
        {
            return tfs != null;
        }

        /// <summary>
        /// Gets the work item store.
        /// </summary>
        /// <param name="tfsAddress">The tfs url.</param>
        /// <param name="sessionId">The session id.</param>
        /// <param name="useCache">The use cache.</param>
        /// <returns>Instance of the work item store</returns>
        private WorkItemStore GetWorkItemStore(string tfsAddress, string sessionId, bool useCache)
        {
            var cacheId = string.Concat(tfsAddress, "__", sessionId);
            WorkItemStore workItemStore;

            // Check the cache for a matching instance
            if (useCache)
            {
                if (this.cachingService.ContainsKey(cacheId))
                {
                    workItemStore = this.cachingService.GetCachedItem<WorkItemStore>(cacheId);
                    if (workItemStore != null)
                    {
                        return workItemStore;
                    }
                }
            }

            // Get the work item store from TFS
            IServiceProvider tfs = null;
            try
            {
                tfs = this.connectionService.GetTfsServiceProvider(tfsAddress);
            }
            catch (Exception ex)
            {
                var serviceException = new ServiceException("Work Item Store Repository", ex);

                if (this.IsSubscribed)
                {
                    this.ExceptionMessage(this, new ExceptionActionEventArgs(serviceException));
                }
                else
                {
                    if (this.IsSubscribed)
                    {
                        this.ExceptionMessage(this, new ExceptionActionEventArgs(serviceException));
                    }

                    throw serviceException;
                }
            }

            if (!HasServerConnection(tfs) || tfs == null)
            {
                return null;
            }

            workItemStore = (WorkItemStore)tfs.GetService(typeof(WorkItemStore));

            if (useCache)
            {
                this.cachingService.CacheObject(cacheId, workItemStore);
            }

            if (this.IsSubscribed)
            {
                this.Message(
                        this, new ActionEventArgs(string.Concat("WorkItemStore service loaded from tfs '", tfsAddress, "'")));
            }

            return workItemStore;
        }
    }
}